/*
	kmain.c

	the 64-bit main setup routine

	Author: Aidan Goddard, 23/4/13
*/

// includes
#include "../kernel/headers/types.h"
#include "../kernel/headers/system_config_tables.h"
#include "../kernel/headers/message_handling.h"
#include "../kernel/headers/CPU_exception.h"

#include "headers/memory_bitmap.h"
#include "headers/printf.h"
#include "headers/ISR.h"
#include "headers/temp_exceptions.h"
#include "headers/IRQ.h"
#include "headers/PCI.h"

// externals
// Spurious ISR vectors
extern void ISR_PIC_SP_7(void);
extern void ISR_PIC_SP_15(void);
extern void ISR_APIC_SP(void);

extern void ISR_APIC_scheduler_timer(void);
extern void ISR_HPET_scheduler_timer(void);

extern uint64_t SYSISR_ISRS;

// system time setting function
extern void SetSystemTime(void);

// main function
int kmain()
{
	// print hello message
	Printf("[RAILGUN] Now booting...");

	// get the memory bitmap
	uint64_t memory_amount = GetMemoryBitmap();
	Printf("\n[RAILGUN] available memory %uB (%uMB)", memory_amount, (uint64_t)(memory_amount / (1024 * 1024)));
	if((memory_amount/(1024 * 1024)) < 510)
	{
		Printf("\n[RAILGUN] ERROR: not enough non-reserved physical memory available. Minumum is 510MB (1GB physical installed).");
		return -1;
	}

	// set up the page access control mechanism
	SetupGlobalPageControl();

	// setup message handlers
	SetupMessageHandler();

	// setup GDT and IDT
	SetupGDT();
	SetupIDT();

	// setup temp CPU exception handlers
	RegisterISR(0, (uint64_t)&CPU_exception_DE, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(1, (uint64_t)&CPU_exception_DB, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(2, (uint64_t)&CPU_exception_NMI, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(3, (uint64_t)&CPU_exception_BP, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(4, (uint64_t)&CPU_exception_OF, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(5, (uint64_t)&CPU_exception_BR, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(6, (uint64_t)&CPU_exception_UD, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(7, (uint64_t)&CPU_exception_NM, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(8, (uint64_t)&CPU_exception_DF, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(10, (uint64_t)&CPU_exception_TS, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(11, (uint64_t)&CPU_exception_NP, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(12, (uint64_t)&CPU_exception_SS, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(13, (uint64_t)&CPU_exception_GP, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(14, (uint64_t)&CPU_exception_PF, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(16, (uint64_t)&CPU_exception_MF, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(17, (uint64_t)&CPU_exception_AC, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(18, (uint64_t)&CPU_exception_MC, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(19, (uint64_t)&CPU_exception_XF, 0x08, CPL_0, GATE_TRAP, IST_2);
	RegisterISR(30, (uint64_t)&CPU_exception_SX, 0x08, CPL_0, GATE_TRAP, IST_2);

	// enumerate the PCI Express bus
	EnumeratePCIEBus();

	// calibrate APIC timer
	CalibrateAPICTimer();

	// setup system IRQs
	SetupSystemIRQs();

	// set the APIC and PIC spurious IRQ ISRs (IRQs use IST_1)
	DisableISR(32 + 7);
	DisableISR(32 + 15);
	RegisterISR(32 + 7, (uint64_t)&ISR_PIC_SP_7, 0x08, CPL_0, GATE_INTERRUPT, IST_1);
	RegisterISR(32 + 15, (uint64_t)&ISR_PIC_SP_15, 0x08, CPL_0, GATE_INTERRUPT, IST_1);
	DisableISR(63);
	RegisterISR(63, (uint64_t)&ISR_APIC_SP, 0x08, CPL_0, GATE_INTERRUPT, IST_1);

	// set the APIC timer IRQ ISR
	DisableISR(50);
	RegisterISR(50, (uint64_t)&ISR_APIC_scheduler_timer, 0x08, CPL_0, GATE_INTERRUPT, IST_1);

	// set the HPET timer IRQ ISR
	DisableISR(49);
	RegisterISR(49, (uint64_t)&ISR_HPET_scheduler_timer, 0x08, CPL_0, GATE_INTERRUPT, IST_1);

	// setup the scheduler data area
	SetupDataArea();

	// setup real CPU exceptions
	DisableISR(0);
	DisableISR(1);
	DisableISR(2);
	DisableISR(3);
	DisableISR(4);
	DisableISR(5);
	DisableISR(6);
	DisableISR(7);
	DisableISR(8);
	DisableISR(10);
	DisableISR(11);
	DisableISR(12);
	DisableISR(13);
	DisableISR(14);
	DisableISR(16);
	DisableISR(17);
	DisableISR(18);
	DisableISR(19);
	DisableISR(30);

	RegisterISR(0, (uint64_t)&CPU_EXCEPTION_0_DE, 0x08, CPL_0, GATE_INTERRUPT, IST_6);	// set as interrupt to disable interrupts during ISR
	RegisterISR(1, (uint64_t)&CPU_EXCEPTION_1_DB, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(2, (uint64_t)&CPU_EXCEPTION_2_NMI, 0x08, CPL_0, GATE_INTERRUPT, IST_5);
	RegisterISR(3, (uint64_t)&CPU_EXCEPTION_3_BP, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(4, (uint64_t)&CPU_EXCEPTION_4_OF, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(5, (uint64_t)&CPU_EXCEPTION_5_BR, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(6, (uint64_t)&CPU_EXCEPTION_6_UD, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(7, (uint64_t)&CPU_EXCEPTION_7_NM, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(8, (uint64_t)&CPU_EXCEPTION_8_DF, 0x08, CPL_0, GATE_INTERRUPT, IST_7);
	RegisterISR(10, (uint64_t)&CPU_EXCEPTION_10_TS, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(11, (uint64_t)&CPU_EXCEPTION_11_NP, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(12, (uint64_t)&CPU_EXCEPTION_12_SS, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(13, (uint64_t)&CPU_EXCEPTION_13_GP, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(14, (uint64_t)&CPU_EXCEPTION_14_PF, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(16, (uint64_t)&CPU_EXCEPTION_16_MF, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(17, (uint64_t)&CPU_EXCEPTION_17_AC, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(18, (uint64_t)&CPU_EXCEPTION_18_MC, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(19, (uint64_t)&CPU_EXCEPTION_19_XF, 0x08, CPL_0, GATE_INTERRUPT, IST_6);
	RegisterISR(30, (uint64_t)&CPU_EXCEPTION_30_SX, 0x08, CPL_0, GATE_INTERRUPT, IST_6);

	// setup Syscall registers and table


	// set the system time
	SetSystemTime();

	// return success
	printf("\n[RAILGUN] System setup success. Now entering scheduler...");

	// start scheduling
	StartScheduling();

	return 0;
}


















